﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Http;
using System.Net;
using System.Collections.Concurrent;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace UniversityCrawler
{
    public partial class Form1 : Form
    {
        private readonly HttpClient _httpClient;
        private CancellationTokenSource _cancellationTokenSource;
        private readonly ConcurrentDictionary<string, List<string>> _phoneNumberUrls;
        private readonly ConcurrentBag<string> _processedUrls;
        private readonly ConcurrentQueue<string> _urlsToProcess;
        private readonly object _lockObject = new object();
        private int _maxConcurrentRequests = 5;
        private int _activeRequests = 0;
        private int _totalUrlsProcessed = 0;
        private bool _isCrawling = false;

        public Form1()
        {
            InitializeComponent();

            // 配置 HttpClient
            var handler = new HttpClientHandler
            {
                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
                AllowAutoRedirect = true
            };

            _httpClient = new HttpClient(handler)
            {
                Timeout = TimeSpan.FromSeconds(15)
            };
            _httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");

            _phoneNumberUrls = new ConcurrentDictionary<string, List<string>>();
            _processedUrls = new ConcurrentBag<string>();
            _urlsToProcess = new ConcurrentQueue<string>();
        }

        private async void btnSearch_Click(object sender, EventArgs e)
        {
            if (_isCrawling)
            {
                // 停止爬虫
                _cancellationTokenSource?.Cancel();
                btnSearch.Text = "搜索";
                _isCrawling = false;
                return;
            }

            string keyword = txtKeyword.Text.Trim();
            if (string.IsNullOrEmpty(keyword))
            {
                MessageBox.Show("请输入搜索关键词", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            // 重置状态
            _phoneNumberUrls.Clear();
            // 清空 ConcurrentBag
            while (!_processedUrls.IsEmpty)
            {
                string item;
                _processedUrls.TryTake(out item);
            }
            while (_urlsToProcess.TryDequeue(out _)) { }

            lstPhoneNumbers.Items.Clear();
            lstUrls.Items.Clear();
            progressBar.Value = 0;
            _totalUrlsProcessed = 0;
            _activeRequests = 0;

            // 开始爬虫
            _isCrawling = true;
            btnSearch.Text = "停止";
            lblStatus.Text = "正在爬取数据...";

            _cancellationTokenSource = new CancellationTokenSource();

            try
            {
                // 添加初始搜索URL
                string baiduSearchUrl = $"https://www.baidu.com/s?wd={Uri.EscapeDataString(keyword)}+大学+电话号码";
                _urlsToProcess.Enqueue(baiduSearchUrl);

                // 开始爬取
                await StartCrawlingAsync(_cancellationTokenSource.Token);
            }
            catch (OperationCanceledException)
            {
                lblStatus.Text = "爬取已取消";
            }
            catch (Exception ex)
            {
                lblStatus.Text = $"发生错误: {ex.Message}";
            }
            finally
            {
                btnSearch.Text = "搜索";
                _isCrawling = false;
            }
        }

        private async Task StartCrawlingAsync(CancellationToken cancellationToken)
        {
            // 创建任务列表
            List<Task> tasks = new List<Task>();

            // 启动爬虫任务
            for (int i = 0; i < _maxConcurrentRequests; i++)
            {
                tasks.Add(Task.Run(async () => await CrawlAsync(cancellationToken), cancellationToken));
            }

            // 等待所有任务完成
            await Task.WhenAll(tasks);

            // 更新界面显示结果
            UpdateUI();
        }

        private async Task CrawlAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested &&
                   (_urlsToProcess.Count > 0 || _activeRequests > 0) &&
                   _phoneNumberUrls.Count < 100)
            {
                string url = null;

                // 尝试获取下一个URL
                if (!_urlsToProcess.TryDequeue(out url))
                {
                    // 队列为空但仍有活动请求，等待一段时间
                    if (_activeRequests > 0)
                    {
                        await Task.Delay(100, cancellationToken);
                        continue;
                    }
                    break;
                }

                // 检查URL是否已处理
                if (_processedUrls.Contains(url))
                {
                    continue;
                }

                // 增加活动请求计数
                Interlocked.Increment(ref _activeRequests);

                try
                {
                    // 获取网页内容
                    string htmlContent = await GetWebPageContentAsync(url, cancellationToken);
                    if (string.IsNullOrEmpty(htmlContent))
                    {
                        continue;
                    }

                    // 提取电话号码
                    ExtractPhoneNumbers(url, htmlContent);

                    // 提取链接并添加到队列
                    ExtractLinks(url, htmlContent);

                    // 记录已处理的URL
                    _processedUrls.Add(url);
                    Interlocked.Increment(ref _totalUrlsProcessed);

                    // 更新进度条
                    UpdateProgressBar();
                }
                catch (Exception ex) when (!(ex is OperationCanceledException))
                {
                    // 记录错误但继续处理其他URL
                    AppendLog($"处理URL时出错: {url}, 错误: {ex.Message}");
                }
                finally
                {
                    // 减少活动请求计数
                    Interlocked.Decrement(ref _activeRequests);
                }

                // 避免请求过于频繁
                await Task.Delay(new Random().Next(500, 1500), cancellationToken);
            }
        }

        private async Task<string> GetWebPageContentAsync(string url, CancellationToken cancellationToken)
        {
            try
            {
                AppendLog($"正在获取: {url}");
                HttpResponseMessage response = await _httpClient.GetAsync(url, cancellationToken);

                if (response.IsSuccessStatusCode)
                {
                    return await response.Content.ReadAsStringAsync();
                }

                AppendLog($"无法获取URL: {url}, 状态码: {response.StatusCode}");
                return null;
            }
            catch (Exception ex) when (!(ex is OperationCanceledException))
            {
                AppendLog($"获取URL时出错: {url}, 错误: {ex.Message}");
                return null;
            }
        }

        private void ExtractPhoneNumbers(string url, string htmlContent)
        {
            if (string.IsNullOrEmpty(htmlContent)) return;

            // 中国大学电话号码模式：区号(3-4位)-电话号码(7-8位)
            // 常见格式: 010-12345678, 0755-1234567, (021)12345678, 021-1234-5678等
            string pattern = @"(?:\(?0\d{2,3}[\)-]?[ -]?\d{7,8})|((?:\+?86)?1\d{10})";

            foreach (Match match in Regex.Matches(htmlContent, pattern))
            {
                string phoneNumber = match.Value.Trim();

                // 标准化电话号码格式
                phoneNumber = Regex.Replace(phoneNumber, @"[^\d]", "");

                // 如果是手机号，确保是11位
                if (phoneNumber.StartsWith("1") && phoneNumber.Length == 11)
                {
                    AddPhoneNumber(phoneNumber, url);
                }
                // 如果是座机号，确保有区号
                else if (phoneNumber.Length >= 10 && phoneNumber.Length <= 12)
                {
                    AddPhoneNumber(phoneNumber, url);
                }
            }
        }

        private void AddPhoneNumber(string phoneNumber, string url)
        {
            if (_phoneNumberUrls.Count >= 100) return;

            _phoneNumberUrls.AddOrUpdate(
                phoneNumber,
                new List<string> { url },
                (_, existingUrls) =>
                {
                    if (!existingUrls.Contains(url))
                    {
                        existingUrls.Add(url);
                    }
                    return existingUrls;
                }
            );

            // 更新UI
            UpdatePhoneNumbersList();
        }

        private void ExtractLinks(string baseUrl, string htmlContent)
        {
            if (string.IsNullOrEmpty(htmlContent)) return;

            // 提取链接
            string pattern = @"<a[^>]*href=[""']([^""']*)[""'][^>]*>";
            foreach (Match match in Regex.Matches(htmlContent, pattern))
            {
                string href = match.Groups[1].Value.Trim();
                if (string.IsNullOrEmpty(href) || href.StartsWith("#") || href.StartsWith("javascript:"))
                {
                    continue;
                }

                try
                {
                    // 构造完整URL
                    Uri uri;
                    if (Uri.TryCreate(new Uri(baseUrl), href, out uri))
                    {
                        string newUrl = uri.AbsoluteUri;

                        // 只处理HTTP和HTTPS链接
                        if ((newUrl.StartsWith("http://") || newUrl.StartsWith("https://")) &&
                            !_processedUrls.Contains(newUrl) &&
                            _phoneNumberUrls.Count < 100)
                        {
                            _urlsToProcess.Enqueue(newUrl);
                        }
                    }
                }
                catch
                {
                    // 忽略无效链接
                }
            }
        }

        private void UpdateProgressBar()
        {
            if (InvokeRequired)
            {
                Invoke(new Action(UpdateProgressBar));
                return;
            }

            // 更新进度条
            int progress = Math.Min(100, (int)(_phoneNumberUrls.Count / 100.0 * 100));
            progressBar.Value = progress;
            lblStatus.Text = $"已找到 {_phoneNumberUrls.Count} 个电话号码，已处理 {_totalUrlsProcessed} 个URL";
        }

        private void UpdatePhoneNumbersList()
        {
            if (InvokeRequired)
            {
                Invoke(new Action(UpdatePhoneNumbersList));
                return;
            }

            lstPhoneNumbers.Items.Clear();
            foreach (var pair in _phoneNumberUrls)
            {
                lstPhoneNumbers.Items.Add($"{pair.Key} (来源: {pair.Value.Count} 个页面)");
            }
        }

        private void UpdateUI()
        {
            if (InvokeRequired)
            {
                Invoke(new Action(UpdateUI));
                return;
            }

            // 更新电话号码列表
            UpdatePhoneNumbersList();

            // 更新URL列表
            lstUrls.Items.Clear();
            foreach (string url in _processedUrls)
            {
                lstUrls.Items.Add(url);
            }

            lblStatus.Text = $"完成！找到 {_phoneNumberUrls.Count} 个电话号码，处理了 {_processedUrls.Count} 个URL";
        }

        private void AppendLog(string message)
        {
            if (InvokeRequired)
            {
                Invoke(new Action<string>(AppendLog), message);
                return;
            }

            txtLog.AppendText(message + Environment.NewLine);
            // 自动滚动到底部
            txtLog.SelectionStart = txtLog.Text.Length;
            txtLog.ScrollToCaret();
        }

        private void lstPhoneNumbers_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lstPhoneNumbers.SelectedIndex < 0) return;

            string selected = lstPhoneNumbers.SelectedItem.ToString();
            string phoneNumber = selected.Split(' ')[0];

            if (_phoneNumberUrls.TryGetValue(phoneNumber, out List<string> urls))
            {
                // 显示该电话号码的来源URL
                lstUrls.Items.Clear();
                foreach (string url in urls)
                {
                    lstUrls.Items.Add(url);
                }
            }
        }

        private void numMaxThreads_ValueChanged(object sender, EventArgs e)
        {
            _maxConcurrentRequests = (int)numMaxThreads.Value;
        }
    }
}